package com.wujunhao1024.sqldp.render;

import com.wujunhao1024.sqldp.SqlDpParser;
import com.wujunhao1024.sqldp.entity.Field;
import guru.nidi.graphviz.attribute.Label;
import guru.nidi.graphviz.engine.Format;
import guru.nidi.graphviz.engine.Graphviz;
import guru.nidi.graphviz.model.MutableGraph;
import guru.nidi.graphviz.model.MutableNode;

import java.io.File;
import java.io.IOException;
import java.util.List;

import static guru.nidi.graphviz.attribute.Attributes.attr;
import static guru.nidi.graphviz.model.Factory.mutGraph;
import static guru.nidi.graphviz.model.Factory.mutNode;

public class RenderUtil {

    public static void render(String sql) throws IOException {
        List<Field> fields = SqlDpParser.parse(sql);

        MutableGraph graph = mutGraph("SQL Parse Tree").setDirected(true);
        MutableNode root = mutNode(sql)
                .add(attr("shape", "box"))
                .add(attr("style", "filled"))
                .add(attr("fillcolor", "#e6f7ff"));
        graph.add(root);

        // 全局样式设置
        graph.graphAttrs().add(attr("rankdir", "TB"));
        graph.nodeAttrs().add(attr("shape", "none"));

        recurse(graph, fields, root, 0);

        Graphviz.fromGraph(graph).render(Format.SVG).toFile(new File("sql_parse_tree.svg"));
        System.out.println("图片已生成：sql_parse_tree.svg");

    }

    private static void recurse(MutableGraph graph, List<Field> fields, MutableNode node, int depth) {
        if (fields == null || fields.isEmpty()) {
            return;
        }
        for (Field field : fields) {
            // 构建 HTML 表格格式的 label
            String htmlLabel = buildHtmlLabel(field);

            // 不同深度用不同颜色区分
            String fillColor = getFillColorByDepth(depth);

            // 创建当前节点并应用样式
            Label label = Label.html(htmlLabel);
            MutableNode curNode = mutNode(label)
                    .add(attr("shape", "none"))
                    .add(attr("style", "filled"))
                    .add(attr("fillcolor", fillColor));

            graph.add(curNode);
            graph.add(node.addLink(curNode)); // 默认无边标签

            // 递归处理子字段
            recurse(graph, field.getSourceFields(), curNode, depth + 1);
        }
    }

    /**
     * 构建 HTML 样式的 label
     *
     * @param field
     * @return
     */
    private static String buildHtmlLabel(Field field) {
        StringBuilder sb = new StringBuilder();
        sb.append("<table border='0' cellborder='1' cellspacing='0'>");

        addRow(sb, "Field", safe(field.getFieldName()));
        addRow(sb, "Table", safe(field.getTableName()));
        addRow(sb, "Field Alias", safe(field.getAliasName()));
        addRow(sb, "Table Alias", safe(field.getInnerAliasTable()));

        sb.append("</table>");
        return sb.toString();
    }

    /**
     * 增加行
     *
     * @param sb
     * @param label
     * @param value
     */
    private static void addRow(StringBuilder sb, String label, String value) {
        sb.append("  <tr>")
                .append("<td bgcolor='#f0f0f0'><b>").append(label).append("</b></td>")
                .append("<td>").append(value != null ? value : "").append("</td>")
                .append("</tr>");
    }

    private static String safe(String str) {
        return safe(str, 20, 40);
    }

    /**
     * 防止空值导致 HTML 渲染异常
     *
     * @param str
     * @return
     */
    private static String safe(String str, int minLen, int maxLen) {
        if (str == null) return "";
        // 先转义 HTML 特殊字符
        String escaped = str.replace("&", "&amp;")
                .replace("<", "&lt;")
                .replace(">", "&gt;")
                .replace("\"", "&quot;")
                .replace("'", "&#39;");

        StringBuilder result = new StringBuilder();
        int length = escaped.length();
        int pos = 0;
        while (pos < length) {
            int end = Math.min(pos + maxLen, length);
            if (end == length) {
                result.append(escaped.substring(pos));
                break;
            }
            // 在 [pos, end] 范围内找最后一个空格
            int wrapPos = -1;
            for (int i = end; i > pos; i--) {
                if (i < length && Character.isWhitespace(escaped.charAt(i))) {
                    wrapPos = i;
                    break;
                }
            }
            if (wrapPos != -1 && wrapPos > pos + minLen) {
                result.append(escaped, pos, wrapPos);
                result.append("<br/>");
                pos = wrapPos + 1;
            } else {
                // 如果找不到合适的空格，就强制在 maxLen 处换行
                result.append(escaped, pos, end);
                result.append("<br/>");
                pos = end;
            }
        }
        return result.toString();
    }

    /**
     * 根据深度返回不同颜色
     */
    private static String getFillColorByDepth(int depth) {
        switch (depth % 4) {
            // 浅黄
            case 0:
                return "#fff8dc";
            // 浅绿
            case 1:
                return "#e6ffe6";
            // 浅蓝
            case 2:
                return "#e6f7ff";
            // 浅粉
            case 3:
                return "#fff0f5";
            default:
                return "#ffffff";
        }
    }
}
